# -*- coding: utf-8 -*-
"""Models for generic web-service"""

# imports
from base64 import b64encode, b64decode

from django.db import models
from django.utils.encoding import smart_str

# uses Sessions Middleware

# users
class User(models.Model):
    """Service user, which may have no account"""
    # model data
    screen_name = models.CharField(blank=True, max_length=50)
    # functional metadata
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)
    # last activity date
    # acted = models.DateTimeField(auto_now=True)
    # last_activity = models.DateTimeField()

    def __unicode__(self):
        if self.screen_name:
            return self.screen_name
        elif self.has_account():
            return self.email_account().email
        else:
            return u'Anonymous #%s' % self.id

    # @return EmailAccount
    def email_account(self):
        try:
            return EmailAccount.objects.get(user=self)
        except EmailAccount.DoesNotExist:
            return None

    # return bool
    def has_account(self):
        if self.email_account():
            return True
        else:
            return False

    # django.ontrib.auth.User compatibility when using RequestContext
    def get_and_delete_messages(self):
        return []

    def is_saved(self):
        if self.id is None:
            return False
        else:
            return True

class EmailAccount(models.Model):
    """User email-based account, allowing to log in"""
    # email used as login
    email = models.EmailField(unique=True)
    # django-style password : hashtype$salt$hash
    password = models.CharField(max_length=128)
    # optional

    # functional metadata
    user = models.OneToOneField(User, editable=False)
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)

    @staticmethod
    def register(user, email, password):
        """
        register user with provided email and password
        try sending an email
        returns created account
        """
        account = EmailAccount(user=user, email=email)
        account.set_password(password)
        account.save()
        return account

    def set_password(self, value, algorithm='sha1'):
        """Sets new password

        stored value will be django-style : algorithm$salt$hash
        salt will be a short random string

        >>> a = EmailAccount()
        >>> a.set_password(u's3cr3t')
        >>> p = a.password
        >>> # password shall not be stored as is
        >>> p == 'secret'
        False
        >>> a.set_password(u's3cr3t')
        >>> # a random salt should be added
        >>> p == a.password
        False
        """
        import hashlib, random
        # creating random salt
        # 5 random chars within this
        base = u'abcdefghijklmnopqrstuvwxyz0123456789'
        salt = u''.join([random.choice(base) for i in range(5)])

        # building hash from salt + value
        to_hash = self._unicode_for_hash(salt + value)
        hash = hashlib.new(algorithm)
        hash.update(to_hash)
        # setting pasword
        self.password = u'$'.join((algorithm, salt, hash.hexdigest()))

    def check_password(self, value):
        """Check password value against stored hash

        >>> a = EmailAccount()
        >>> a.set_password(u's3cr3t')
        >>> a.check_password(u's3cr3t')
        True
        >>> a.check_password(u'guess')
        False"""
        import hashlib
        algorithm, salt, hash = self.password.split(u'$')
        # return check
        value = self._unicode_for_hash(salt + value)
        value_hash = hashlib.new(algorithm)
        value_hash.update(value)
        return value_hash.hexdigest() == hash

    #def send_email(self, subject, content, from_email):
    #    """sends an email to account"""
    #    pass

    def _unicode_for_hash(self, unicode):
        # converts unicode to hashable
        return str([ord(c) for c in unicode])

#class UserData(models.Model):
#    """Preferences et données utilisateur"""
#    user = models.OneToOneField(User)
#
#    email = models.EmailField(blank=True)

class Invitation(models.Model):
    """Used while in closed beta, allows user creation"""
    code = models.CharField(max_length=32)